#pragma once
#include <cuda.h>
#include <cuda_runtime_api.h>
#include <math_constants.h>
#include "../raycast/math.hpp"
#include "math.h"
// inline __host__ __device__ float dot(float3 p1, float3 p2)
// {
//     return p1.x * p2.x + p1.y * p2.y + p1.z * p2.z;
// }

// inline __host__ __device__ float3 operator*(float3 a, float b)
// {
//     return make_float3(a.x * b, a.y * b, a.z * b);
// }

// inline __host__ __device__ float3 operator*(const float3 &a,const float &b)const
// {
//     return make_float3(a.x * b, a.y * b, a.z * b);
// }
inline __host__ __device__ float3 operator/(float3 a, float b)
{
    return make_float3(a.x / b, a.y / b, a.z / b);
}
inline __host__ __device__ float3 operator*(int3 a, float b)
{
    return make_float3(a.x * b, a.y * b, a.z * b);
}
inline __host__ __device__ float3 operator*(uint3 a, float b)
{
    return make_float3(a.x * b, a.y * b, a.z * b);
}

// inline __host__ __device__ void operator+=(float3 &b, const float3 &a)
// {
//     b.x += a.x, b.y += a.y, b.z += a.z;
//     // b = make_float3(b.x + a.x, b.y + a.y, b.z + a.z);
//     // return b;
// }
inline __host__ __device__ float operator*(float4 &b, float3 &a)
{
    return (b.x * a.x + b.y * a.y + b.z * a.z);
}

#define COMPOUND_VEC3_OP(type, scalar, op)                                          \
    __device__ __host__ __forceinline__ type &operator op(type &v1, const type &v2) \
    {                                                                               \
        v1.x op v2.x;                                                               \
        v1.y op v2.y;                                                               \
        v1.z op v2.z;                                                               \
        return v1;                                                                  \
    }                                                                               \
    __device__ __host__ __forceinline__ type &operator op(type &v, scalar val)      \
    {                                                                               \
        v.x op val;                                                                 \
        v.y op val;                                                                 \
        v.z op val;                                                                 \
        return v;                                                                   \
    }

#define FOR_VEC3_OP(type, scalar, op)                                               \
    __device__ __host__ __forceinline__ type &operator op(type &v1, const type &v2) \
    {                                                                               \
        v1.x op v2.x;                                                               \
        v1.y op v2.y;                                                               \
        v1.z op v2.z;                                                               \
        return v1;                                                                  \
    }                                                                               \
    __device__ __host__ __forceinline__ type &operator op(type &v, scalar val)      \
    {                                                                               \
        v.x op val;                                                                 \
        v.y op val;                                                                 \
        v.z op val;                                                                 \
        return v;                                                                   \
    }

COMPOUND_VEC3_OP(float3, float, -=)
// COMPOUND_VEC3_OP(float3, float, +=)
COMPOUND_VEC3_OP(float3, float, *=)

COMPOUND_VEC3_OP(short3, short, -=)

COMPOUND_VEC3_OP(int3, int, +=)

#undef COMPOUND_VEC3_OP


inline __host__ __device__ float3 cross(float3 a, float3 b)
{
    return make_float3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
}

